package SVN::TeamTools::Plugins::Doc;

use warnings;
use strict;
use Carp;
use Error qw(:try);

use SVN::TeamTools::Store::Config;
use SVN::TeamTools::Store::SvnIndex;
use SVN::TeamTools::Store::DepIndex;
use SVN::TeamTools::Store::Repo;

use HTML::Template;
use CGI;
use URI::Escape;
use Data::Dumper;

my $conf;
my $logger;
BEGIN { $conf = SVN::TeamTools::Store::Config->new(); $logger = $conf->{logger}; }

my $breakoff = "|web|build|";
my $filter;

sub hasAction {
	shift;
	my %args	= @_;
	my $action	= $args{action};
	return ("|dsp.doc|get.doc.detail|get.doc.source|get.doc.whereused|get.doc.dependson|get.doc.diff|" =~ /\|\Q$action\E\|/);
}

sub getTemplate {
	shift;
	my %args	= @_;
	my $action	= $args{action};
	my $cgi		= $args{cgi};

	my $rev;
	if ( defined $cgi->param("rev") and $cgi->param("rev") =~ /[0-9]+/ ) {
		$rev = $cgi->param("rev");
		$logger->debug("Got revision $rev");
	} else {
		my $repo = SVN::TeamTools::Store::Repo->new();
		$rev = $repo->getSvnRev();
		$logger->debug("fetched revision $rev");
	}

	my $template = HTML::Template->new( filename => 'SVN/TeamTools/Plugins/tmpl/doc.tmpl', path => @INC );
	if ( defined $cgi->param("page") ) {
		$template->param(p_page => $cgi->param("page"));
	} else {
		$template->param(p_page => "source");
	}
	$template->param (p_rev => $rev);
	$template->param (p_url => $conf->{config}->{svn}->{url});
	return $template;
}

sub getData {
	shift;
	my %args	= @_;
	my $action	= $args{action};
	my $param	= $args{param};

	my $repo	= SVN::TeamTools::Store::Repo->new();
	my $rev;
	if ( defined $param->{rev} and $param->{rev} =~ /[0-9]+/ ) {
		$rev = $param->{rev};
	} else {
		$rev = $repo->getSvnRev();
	}
	my $svnlook	= $repo->getLook (rev => $rev);

	my %result;
	if ($action =~ /get.doc.detail/ ) {
		my $props	= $svnlook->proplist ($param->{path});
		my @t_hist	= $svnlook->_svnlook("history",$param->{path});
		shift(@t_hist);
		shift(@t_hist);
		my @hist;
		for my $line (@t_hist) {
			$line =~ /\s*([^\s]+)\s+([^\s][\s\S]+)$/;
			my $t_rev = $1;
			my $t_path = $2;
			my $t_look = $repo->getLook(rev=>$t_rev);
			push (@hist, {
				rev	=> $t_rev,
				path	=> $t_path,
				author	=> $t_look->author(),
				date	=> $t_look->date(),
			});
		}
		%result = (
			author	=> $svnlook->author(),
			date	=> $svnlook->date(),
			props	=> $props,
			hist	=> \@hist,
		);
		return \%result;
	} elsif ($action =~ /get.doc.source/) {
        	$param->{path}	=~ /\.([^\/\.]+)$/;
	        my $ext         = $1;
        	my $lang        = $conf->{src_types}->{$ext}->{color};
	        my $rawsource   = $repo->svnCat(rev => $rev,path => $param->{path});

		%result = (
			ext	=> $ext,
			lang	=> $lang,
			source	=> $rawsource,
		);
		return \%result;
	} elsif ($action =~ /get.doc.whereused/) {
		my $depindex	= SVN::TeamTools::Store::DepIndex->new(mode=>"r",create=>0);

		$param->{path} =~ /\/([^\/]+)\.[^\/\.]+$/;
		my $module = $1;

		$logger->debug("Analysing module path for context");
		for my $reg (@{$conf->{config}->{trees}->{treeregex}}) {
			if ($param->{path} =~ m#($reg)#) {
				$filter = $1;
				$logger->debug("Tree $param->{path} matched $reg as $1");
			} else {
				$logger->debug("Tree $param->{path} not matched $reg");
			}
		}
				

		my $maxdepth = (defined $param->{wumaxdepth} ? $param->{wumaxdepth} : 5);
		my $wu = whereused (depindex => $depindex, rev => $rev, path => $param->{path}, module => $module, depth => 0, maxdepth => $maxdepth);
		$wu->{filter} = $filter;
		$wu->{maxdepth} = $maxdepth;
		return $wu;
	} elsif ($action =~ /get.doc.dependson/) {
		my $depindex	= SVN::TeamTools::Store::DepIndex->new(mode=>"r",create=>0);
		my $svnindex	= SVN::TeamTools::Store::SvnIndex->new(mode=>"r",create=>0);

		$param->{path} =~ /\/([^\/]+)\.[^\/\.]+$/;
		my $module = $1;

		$logger->debug("Analysing module path for context");
		for my $reg (@{$conf->{config}->{trees}->{treeregex}}) {
			if ($param->{path} =~ m#($reg)#) {
				$filter = $1;
				$logger->debug("Tree $param->{path} matched $reg as $1");
			} else {
				$logger->debug("Tree $param->{path} not matched $reg");
			}
		}
				
		my $maxdepth = (defined $param->{domaxdepth} ? $param->{domaxdepth} : 3);
		my $do = dependson (depindex => $depindex, svnindex => $svnindex, rev => $rev, path => $param->{path}, module => $module, depth => 0, maxdepth => $maxdepth);
		$do->{filter} = $filter;
		$do->{maxdepth} = $maxdepth;
		return $do;
	} elsif ($action =~ /get.doc.diff/) {
		my $oldrev;
		my $oldpath;
		if ($param->{oldrev} =~ /^0$/) { # Compare against prev revision
			my @t_hist	= $svnlook->_svnlook("history",$param->{path});
			shift(@t_hist);
			shift(@t_hist);
			my $line = shift (@t_hist);
			$line =~ /\s*([^\s]+)\s+([^\s][\s\S]+)$/;
			$oldrev = $1;
			$oldpath = $2;
			if ( $rev =~ /$oldrev/ ) {
				$line = shift (@t_hist);
				$line =~ /\s*([^\s]+)\s+([^\s][\s\S]+)$/;
				$oldrev = $1;
				$oldpath = $2;
			}
		} else {
			$oldrev = $param->{oldrev};
			$oldpath = $param->{oldpath};
		}
	
		my $src_new = $repo->svnCat(rev=>$rev, path=>$param->{path});
		my $src_old = $repo->svnCat(rev=>$oldrev, path=>$oldpath);

		%result = (
			old_rev => $oldrev,
			old_path => $oldpath,
			old_src => $src_old,
			new_rev => $rev,
			new_path => $param->{path},
			new_src => $src_new,
		);

		return \%result;
	}

}

sub whereused {
	my %args	= @_;
	my $depindex	= $args{depindex};
	my $rev		= $args{rev};
	my $path	= $args{path};
	my $module	= $args{module};
	my $depth	= $args{depth};
	my $maxdepth	= $args{maxdepth};

	my @subtree;
	if ( $depth < $maxdepth ) {
		my @deps;
		my $res = $depindex->execANDQuery( queries => [ $depindex->getTermQuery(field => 'module',term => $module) ]);
		while (my $r = $res->next()) {
			$logger->debug("found ".$r->{module});
			if ($r->{path} =~ /^\Q$filter\E/) {
				push (@deps, $r->{path});
			}
		}
		if (scalar(@deps)) {
			foreach my $dep (@deps) {
                                $dep =~ /\/([^\/]+)\.[^\/\.]+$/;
                                my $m = $1;
				if ( $breakoff !~ /\|$m\|/i ) {
					$breakoff = $breakoff . $m . "|";
					push (@subtree,whereused (depindex => $depindex, rev => $rev, path => $dep, module => $m, depth => $depth + 1, maxdepth => $maxdepth));
				}
			}
		}
	}
	my %tree = ( module => $module, path => $path, rev => $rev, subtree => \@subtree);
	return \%tree
}

sub dependson {
	my %args	= @_;
	my $depindex	= $args{depindex};
	my $svnindex	= $args{svnindex};
	my $rev		= $args{rev};
	my $path	= $args{path};
	my $module	= $args{module};
	my $depth	= $args{depth};
	my $maxdepth	= $args{maxdepth};

	my @subtree;
	$logger->debug("Analysing deps");
	if ( $depth < $maxdepth ) {
	        my @result;
	        my $res = $depindex->execANDQuery( queries => [ $depindex->getTermQuery(field => 'path',term => $path) ]);
	        while (my $r = $res->next()) {
			$logger->debug("found ".$r->{module});
        	        my $occurences = $svnindex->execANDQuery( queries => [ $svnindex->getTermQuery(field => 'module',term => $r->{module}) ]);
                	while (my $occurence = $occurences->next()) {
                        	if ($occurence->{path} =~ /^\Q$filter\E/) {
	                                push (@result, $occurence->{path});
					last;
        	                }
                	}
	        }
		my %seen;
		my @deps;
		push(@deps, grep { !$seen{$_}++ } @result);
		## $logger->debug("result ".join(',',@result));

		if (scalar(@deps)) {
			foreach my $dep (@deps) {
                                $dep =~ /\/([^\/]+)\.[^\/\.]+$/;
                                my $m = $1;
				if ( $breakoff !~ /\|$m\|/i ) {
					$breakoff = $breakoff . $m . "|";
					push (@subtree,dependson (depindex => $depindex, svnindex => $svnindex, rev => $rev, path => $dep, module => $m, depth => $depth + 1, maxdepth => $maxdepth));
				}
			}
		}
	}
	my %tree = ( module => $module, path => $path, rev => $rev, subtree => \@subtree);
	return \%tree
}
1;
